using System;
#if WINDOWS
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
#elif WINDOWS_PHONE
using System.Xml.Serialization;
using System.Collections.Generic;
#endif
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if WINDOWS_PHONE
using System.Xml;
using System.Xml.Linq;
using System.IO.IsolatedStorage;
using System.IO;
using System.Linq;
#endif


namespace GameFirst
{
    public struct Configuration 
    {
        // [XmlElement]
       //public List<AirSimulation.Aereo> Aerei;
       // [XmlElement]
        //public List<AirSimulation.Proiettile> Proiettili;
        public float Points;
        public float NumProiettili;
        public float EspX;
        public float EspY;
        public float Level;
        public float VminAerei;
        public int VmaxAerei;
        public Configuration(float Points, float NumProiettili, float EspX, float EspY, float Level, float VminAerei, int VmaxAerei)
        {
            this.Points = Points;
            //this.Aerei = Aerei;
            //this.Proiettili = Proiettili;
            this.NumProiettili = NumProiettili;
            this.EspX = EspX;
            this.EspY = EspY;
            this.Level = Level;
            this.VminAerei = VminAerei;
            this.VmaxAerei = VmaxAerei;
        }

    }

    public sealed class GameLogic : Microsoft.Xna.Framework.GameComponent
    {
        float dt;
        renderingdata r2;
        Game G;
        float espX;
        float espY;
        float pausaX;
        float pausaY;
        float timeLevelChange;
        float LevelActual;

        public GameLogic(Game game)
            : base(game)
        {
            
            
            
            //ricarica il file che era stato salvato quando era uscito altrimenti ne crea uno nuovo
            if (menucomp.SaveExist)
            {
#if WINDOWS
                using (Stream stream = File.Open("savegame.sav", FileMode.Open))
                {
                    BinaryFormatter binform = new BinaryFormatter();
                    AirSimulation.statechange = (AirSimulation.GameState)binform.Deserialize(stream);
                }
#elif WINDOWS_PHONE
                Configuration confignew;
                using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (var streamFile = appStorage.OpenFile("savegame.xml", FileMode.OpenOrCreate))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
                        using (var reader = new StreamReader(streamFile))
                            confignew = (Configuration) serializer.Deserialize(reader);
                    }
                }
                AirSimulation.Azzera();
                AirSimulation.statechange.Points = confignew.Points;
                AirSimulation.statechange.Level = confignew.Level;
                AirSimulation.statechange.EspX = confignew.EspX;
                AirSimulation.statechange.EspY = confignew.EspY;
                AirSimulation.statechange.VminAerei = confignew.VminAerei;
                AirSimulation.statechange.VmaxAerei = confignew.VmaxAerei;
                AirSimulation.statechange.NumProiettili = confignew.NumProiettili;

                //altri metodi di caricamento simili
                //1
                //Configuration confignew;
                //XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
                //string configFile = "Config.car";
                //IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication();
                //// If the requested configuration doesn't exists, return default configuration
                //if (appStorage.FileExists(configFile))
                //    Console.WriteLine("sfasfsdfsdvddddddddddddddddddddddddddddddddddddddddddddd");
                //IsolatedStorageFileStream filestream = appStorage.OpenFile(configFile, FileMode.Open, FileAccess.Read);
                //// Deserialize the XML file 
                //confignew = (Configuration)serializer.Deserialize(filestream);
                //AirSimulation.statechange.Points = confignew.Points;
                //AirSimulation.statechange.Aerei.Value.Concat(confignew.Aerei);
                //filestream.Close();
                //2
                //IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
                //IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("savegame.xml", System.IO.FileMode.Open);
                //XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
                //confignew = (Configuration)serializer.Deserialize(stream);
                //stream.Close();
                //3
                //try
                //{
                //    using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
                //    {
                //        if (myIsolatedStorage.FileExists("savegame.xml"))
                //            System.Console.WriteLine("sfasfsdfsdvddddddddddddddddddddddddddddddddddddddddddddd");
                //        using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("savegame.xml", FileMode.Open))
                //        {
                //            XmlSerializer serializer = new XmlSerializer(typeof(AirSimulation.GameState));
                //            AirSimulation.statechange = (AirSimulation.GameState)serializer.Deserialize(stream);
                //        }
                //    }
                //}
                //catch
                //{ }
                //4
                //XmlSerializer mySerializer = new XmlSerializer(typeof(AirSimulation.GameState));
                //FileStream myFileStream = new FileStream("myFileName.xml", FileMode.Open);
                //AirSimulation.statechange = (AirSimulation.GameState)mySerializer.Deserialize(myFileStream);
#endif
            }
            G = game;
            //coordinate ultima esplosione
            espX = -1000.0f;
            espY = -1000.0f;
            pausaX = -1000.0f;
            pausaY = -1000.0f;

            timeLevelChange = 0;
            //-1 così compare all'inizio la scritta "level 0 start"
            LevelActual = -1;

        }


        public override void Initialize()
        {
            r2 = (renderingdata)Game.Services.GetService(typeof(renderingdata));
            //quando esce salva old
            //Game.Exiting += new EventHandler<EventArgs>(gemExitSave);
            base.Initialize();
        }



        //quando esce salva
        //public void gemExitSave(object sender, EventArgs e)
        //salvataggi nuovi
        public static void GameSave()
        {
            #if WINDOWS
            using (Stream stream = File.Open("savegame.sav", FileMode.Create))
            {
                BinaryFormatter binform = new BinaryFormatter();
                binform.Serialize(stream, AirSimulation.statechange);
            }
            #elif WINDOWS_PHONE
            //List<AirSimulation.Aereo> Aerei = new List<AirSimulation.Aereo>();
            //foreach (var a in AirSimulation.statechange.Aerei.Value)
            //    Aerei.Add(a);
            //List<AirSimulation.Proiettile> Proiettili = new List<AirSimulation.Proiettile>();
            //foreach (var p in AirSimulation.statechange.Proiettili.Value)
            //    Proiettili.Add(p);

            Configuration save = new Configuration(AirSimulation.statechange.Points, AirSimulation.statechange.NumProiettili, AirSimulation.statechange.EspX, AirSimulation.statechange.EspY, AirSimulation.statechange.Level, AirSimulation.statechange.VminAerei, AirSimulation.statechange.VmaxAerei);
            using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                appStorage.DeleteFile("savegame.xml");
                using (IsolatedStorageFileStream streamFile = appStorage.OpenFile("savegame.xml", FileMode.OpenOrCreate))
                using (StreamWriter writer = new StreamWriter(streamFile))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
                    serializer.Serialize(writer, save);
                }
            }
            //altri metodi di salvataggio simili
            //1
            //XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
            //string configFile = "Config.car";
            //IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication();
            //// Replace the existing saved configuration with the new one
            //if (appStorage.FileExists(configFile))
            //    appStorage.DeleteFile(configFile);
            //IsolatedStorageFileStream streamFile = appStorage.OpenFile(configFile, FileMode.OpenOrCreate);
            //StreamWriter writer = new StreamWriter(streamFile);
            //serializer.Serialize(writer, save);
            //writer.Close();
            //2
            //IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            //IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("savegame.xml", FileMode.Create);
            //XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
            //serializer.Serialize(stream, save);
            //stream.Close();
            //3
            //XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            //xmlWriterSettings.Indent = true;

            //using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
            //{
            //    using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("savegame.xml", FileMode.Create))
            //    {
            //        XmlSerializer serializer = new XmlSerializer(typeof(AirSimulation.GameState));
            //        using (XmlWriter xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
            //        {
            //            serializer.Serialize(xmlWriter, AirSimulation.statechange);
            //        }
            //    }
            //}
            //4
            //XmlSerializer mySerializer = new XmlSerializer(typeof(AirSimulation.GameState));
            //StreamWriter myWriter = new StreamWriter("myFileName.xml");
            //mySerializer.Serialize(myWriter, AirSimulation.statechange);

#endif
        }


        public override void Update(GameTime gameTime)
        {
            if (r2 == null)
            {
                r2 = (renderingdata)Game.Services.GetService(typeof(renderingdata));
                r2.giainpausa = false;
                r2.PauX = -1000.0f;
                r2.PauY = -1000.0f;
                dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
                //inizializzo le dimensioni dle pannello con dei valori che contengono al suo interno anche le dimensioni degli aerei
                AirSimulation.resolution(r2.MaxX, r2.MaxY, r2.MinX, r2.MinY);
                //inizializzo le dimensioni in f# con posizioni molto distanti dalla schena di gioco così non si eliminano a vicenda in automatico,e i raggi delle sfere x le collisioni
                AirSimulation.inizializationBSphere(new BoundingBox(new Vector3(5000.0f, 5000.0f, 5000.0f), new Vector3(5000.0f, 5000.0f, 5000.0f)), new BoundingSphere(new Vector3(-5000.0f, -5000.0f, -5000.0f), r2.meshRoccia.BoundingSphere.Radius / 3.9f ), (float) r2.meshAereo.BoundingSphere.Radius);
            }
            r2.pauSelez = false;

            #if WINDOWS
            if (InputGame.InputManagerGame.GetState().F1)
                GameSave();
            #endif

            //chiamata ad f# vecchia
            //aereo.bird = AirSimulation.update_bird(aereo.bird, dt, r2.MaxY, r2.MaxX);
            
            //controllo livello
            if (AirSimulation.statechange.Level != LevelActual)
            {
                if ((int)AirSimulation.statechange.Level == 4)
                {
                    r2.changelevel = true;
                    if (InputGame.InputManagerGame.GetState().click)
                    {
                        while (Game.Components.Count > 0)
                        {
                            ((GameComponent)Game.Components[0]).Dispose();
                        }

                        Game.Components.Clear();

                        Game.Components.Add(new menu(Game));
                        Game.Components.Add(new InputGame.InputManagerGame(Game));
                    }
                }
                else
                {
                    timeLevelChange = timeLevelChange + dt;
                    r2.changelevel = true;
                    if (timeLevelChange > 3.0f)
                    {
                        r2.changelevel = false;
                        LevelActual = AirSimulation.statechange.Level;
                        timeLevelChange = 0;
                        //azzero animazioni
                        for (int i = 0; i < r2.numeroMaxEsp; i++)
                        {
                            r2.Animations[i] = null;
                        }
                        r2.animation_count = 0;
                        espX = -1000.0f;
                        espY = -1000.0f;
                        
                    }
                }
            }
            else
            {
                //PAUSE
                if (r2.giainpausa == false)
                {
                    if ((InputGame.InputManagerGame.GetState().mouseX < ((int)(G.GraphicsDevice.Viewport.Width / 42.5f) + (int)(G.GraphicsDevice.Viewport.Width / 3.5f))) && (InputGame.InputManagerGame.GetState().mouseX > ((int)(G.GraphicsDevice.Viewport.Width / 42.5f))))
                    {
                        if ((InputGame.InputManagerGame.GetState().mouseY < (G.GraphicsDevice.Viewport.Height / 2 + (int)(G.GraphicsDevice.Viewport.Height / 2.8f) + G.GraphicsDevice.Viewport.Height / 8)) && (InputGame.InputManagerGame.GetState().mouseY > (G.GraphicsDevice.Viewport.Height / 2 + (int)(G.GraphicsDevice.Viewport.Height / 2.8f))))
                        {
                            r2.pauSelez = true;
                            if (InputGame.InputManagerGame.GetState().click)
                            {
                                pausaX = InputGame.InputManagerGame.GetState().mouseX;
                                pausaY = InputGame.InputManagerGame.GetState().mouseY;
                                r2.giainpausa = true;
                                Game.Components.Add(new Pausa(Game));

                            }
                        }
                    }
                }
                //RIPRENDO GIOCO SE NON SONO IN PAUSA
                if(r2.giainpausa == false)
                {
                    if ((InputGame.InputManagerGame.GetState().mouseY != pausaY) && (InputGame.InputManagerGame.GetState().mouseX != pausaX))
                    {
                        if ((InputGame.InputManagerGame.GetState().mouseY != r2.PauY) && (InputGame.InputManagerGame.GetState().mouseX != r2.PauX))
                        {
                            //nuove chiamate ad f#
                            AirSimulation.update_state(dt);
                            AirSimulation.update_script();
                            Math.commit_variable_updates();
                            r2.finepausa = false;
                            pausaX = -1000.0f;
                            pausaY = -1000.0f;
                            r2.PauX = -1000.0f;
                            r2.PauY = -1000.0f;
                        }
                    }
                }
            }
            

            //ANIMAZIONE ESPLOSIONE
            //controllo se quell'esplosione l'ho già registrata
            if ((espX != AirSimulation.statechange.EspX) && (espY != AirSimulation.statechange.EspY))
            {
                //SUONO esplosione aereo
                r2.soundExplosionI.Dispose();
                r2.soundExplosionI= r2.soundExplosion.CreateInstance();//distruggo e ricreo perchè il soundInstance prima di rieffetture play aspetta che il suono temini, per effettuare play di nuovo questo è l'unico modo
                r2.soundExplosionI.Volume = menucomp.SongG;
                r2.soundExplosionI.Play();

                //registro una nuova esplosione
                if (r2.animation_count == r2.numeroMaxEsp)
                {
                    r2.animation_count = 0;
                }
                r2.Animations[r2.animation_count] = new Animationsprite(G);
                espX = AirSimulation.statechange.EspX;
                espY = AirSimulation.statechange.EspY;
                r2.AnimX[r2.animation_count] = espX;
                r2.AnimY[r2.animation_count] = espY;
                r2.animation_count++;
            }
                
            //aggiorno lo stato di tutte le esplosioni
            for (int i = 0; i < r2.animation_count; i++)
            {
                if (r2.Animations[i].getEndAnimation() == false)
                    r2.Animations[i].UpdateAni(gameTime);
            }
            

            #if WINDOWS
            //torno nel menù
            if (InputGame.InputManagerGame.GetState().Back)
            {
                while (Game.Components.Count > 0)
                {
                    ((GameComponent)Game.Components[0]).Dispose();
                }

                Game.Components.Clear();

                Game.Components.Add(new menu(Game));
                Game.Components.Add(new InputGame.InputManagerGame(Game));
            }
            #endif
            base.Update(gameTime);
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

    }
}
